import {
  isDocument as S,
  isNode as i,
  isPair as m,
  isCollection as y,
  isMap as C,
  isSeq as K,
  isScalar as R,
  isAlias as w,
} from './nodes/identity.js';
const a = Symbol('break visit'),
  z = Symbol('skip children'),
  s = Symbol('remove node');
function O(e, l) {
  const c = A(l);
  S(e)
    ? r(null, e.contents, c, Object.freeze([e])) === s && (e.contents = null)
    : r(null, e, c, Object.freeze([]));
}
O.BREAK = a;
O.SKIP = z;
O.REMOVE = s;
function r(e, l, c, f) {
  const u = M(e, l, c, f);
  if (i(u) || m(u)) return N(e, f, u), r(e, u, c, f);
  if (typeof u != 'symbol') {
    if (y(l)) {
      f = Object.freeze(f.concat(l));
      for (let n = 0; n < l.items.length; ++n) {
        const t = r(n, l.items[n], c, f);
        if (typeof t == 'number') n = t - 1;
        else {
          if (t === a) return a;
          t === s && (l.items.splice(n, 1), (n -= 1));
        }
      }
    } else if (m(l)) {
      f = Object.freeze(f.concat(l));
      const n = r('key', l.key, c, f);
      if (n === a) return a;
      n === s && (l.key = null);
      const t = r('value', l.value, c, f);
      if (t === a) return a;
      t === s && (l.value = null);
    }
  }
  return u;
}
async function j(e, l) {
  const c = A(l);
  S(e)
    ? (await b(null, e.contents, c, Object.freeze([e]))) === s &&
      (e.contents = null)
    : await b(null, e, c, Object.freeze([]));
}
j.BREAK = a;
j.SKIP = z;
j.REMOVE = s;
async function b(e, l, c, f) {
  const u = await M(e, l, c, f);
  if (i(u) || m(u)) return N(e, f, u), b(e, u, c, f);
  if (typeof u != 'symbol') {
    if (y(l)) {
      f = Object.freeze(f.concat(l));
      for (let n = 0; n < l.items.length; ++n) {
        const t = await b(n, l.items[n], c, f);
        if (typeof t == 'number') n = t - 1;
        else {
          if (t === a) return a;
          t === s && (l.items.splice(n, 1), (n -= 1));
        }
      }
    } else if (m(l)) {
      f = Object.freeze(f.concat(l));
      const n = await b('key', l.key, c, f);
      if (n === a) return a;
      n === s && (l.key = null);
      const t = await b('value', l.value, c, f);
      if (t === a) return a;
      t === s && (l.value = null);
    }
  }
  return u;
}
function A(e) {
  return typeof e == 'object' && (e.Collection || e.Node || e.Value)
    ? Object.assign(
        {
          Alias: e.Node,
          Map: e.Node,
          Scalar: e.Node,
          Seq: e.Node,
        },
        e.Value && {
          Map: e.Value,
          Scalar: e.Value,
          Seq: e.Value,
        },
        e.Collection && {
          Map: e.Collection,
          Seq: e.Collection,
        },
        e,
      )
    : e;
}
function M(e, l, c, f) {
  var u, n, t, E, V;
  if (typeof c == 'function') return c(e, l, f);
  if (C(l)) return (u = c.Map) == null ? void 0 : u.call(c, e, l, f);
  if (K(l)) return (n = c.Seq) == null ? void 0 : n.call(c, e, l, f);
  if (m(l)) return (t = c.Pair) == null ? void 0 : t.call(c, e, l, f);
  if (R(l)) return (E = c.Scalar) == null ? void 0 : E.call(c, e, l, f);
  if (w(l)) return (V = c.Alias) == null ? void 0 : V.call(c, e, l, f);
}
function N(e, l, c) {
  const f = l[l.length - 1];
  if (y(f)) f.items[e] = c;
  else if (m(f)) e === 'key' ? (f.key = c) : (f.value = c);
  else if (S(f)) f.contents = c;
  else {
    const u = w(f) ? 'alias' : 'scalar';
    throw new Error(`Cannot replace node with ${u} parent`);
  }
}
export { O as visit, j as visitAsync };
